package com.chuyu.cy.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chuyu.cy.contants.Constant;
import com.chuyu.cy.contants.ResponseCodeEnum;
import com.chuyu.cy.entity.domain.User;
import com.chuyu.cy.entity.dto.LoginDTO;
import com.chuyu.cy.entity.dto.RecommendDTO;
import com.chuyu.cy.entity.dto.UserDTO;
import com.chuyu.cy.entity.vo.LoginVO;
import com.chuyu.cy.entity.vo.UserVo;
import com.chuyu.cy.exception.CustomException;
import com.chuyu.cy.mapper.UserMapper;
import com.chuyu.cy.service.UserService;
import com.chuyu.cy.utils.ArithmeticUtils;
import com.chuyu.cy.utils.Common;
import com.chuyu.cy.utils.LoginObject;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
* @author 周小白
* @description 针对表【user(用户表)】的数据库操作Service实现
*/
@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{

    @Resource
    private UserMapper userMapper;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;



    /**
     * 添加用户
     * @param userDTO 用户信息
     * @return 添加结果
     */
    @Override
    public UserVo addUser(UserDTO userDTO) {

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getStuId, userDTO.getStuId());
        User userInDb = userMapper.selectOne(queryWrapper);
        if (userInDb != null) {
            throw new CustomException("此学号已存在");
        }

        User user = new User();
        user.setNickName(userDTO.getNickName());
        user.setStuId(userDTO.getStuId());
        user.setAvatar(userDTO.getAvatar());
        user.setGender(userDTO.getGender());
        user.setContact(userDTO.getContact());
        user.setTags(userDTO.getTags());
        user.setDescription(userDTO.getDescription());
        user.setCreditScore(100);

        int inserted = userMapper.insert(user);
        if (inserted == 0) {
            throw new CustomException("添加失败");
        }

        return Common.userToUserVo(user);
    }




    /**
     * 获取用户信息
     * @param id 用户id
     * @return 用户信息
     */
    @Override
    public UserVo getUserInfo(Integer id) {
        if (id == null) {
            throw new CustomException("用户id不能为空");
        }

        User user = userMapper.selectById(id);
        if (user == null) {
            throw new CustomException("用户不存在");
        }

        return Common.userToUserVo(user);
    }




    /**
     * 更新用户信息
     * @param userDTO 用户信息
     * @return 更新结果
     */
    @Override
    public Boolean updateUserInfo(UserDTO userDTO) {
        if (userDTO.getId() == null) {
            throw new CustomException("用户id不能为空");
        }

        User user = new User();
        user.setId(userDTO.getId());
        user.setNickName(userDTO.getNickName());
        user.setStuId(userDTO.getStuId());
        user.setAvatar(userDTO.getAvatar());
        user.setGender(userDTO.getGender());
        user.setContact(userDTO.getContact());
        user.setTags(userDTO.getTags());
        user.setDescription(userDTO.getDescription());

        User userInDb = userMapper.selectById(userDTO.getId());
        if (userInDb == null) {
            throw new CustomException("用户不存在");
        }

        int updated = userMapper.updateById(user);
        if (updated == 0) {
            throw new CustomException("更新失败");
        }

        return true;
    }




    /**
     * 删除用户
     * @param id 用户id
     * @return 删除结果
     */
    @Override
    public Boolean deleteUser(Integer id) {
        if (id == null) {
            throw new CustomException("用户id不能为空");
        }

        int deleted = userMapper.deleteById(id);
        if (deleted == 0) {
            throw new CustomException("删除失败");
        }

        return true;
    }




    /**
     * 推荐用户
     * @param recommendDTO 推荐要求
     * @return 结果
     */
    @Override
    public UserVo recommend(RecommendDTO recommendDTO) {
        if (recommendDTO == null) {
            throw new CustomException(ResponseCodeEnum.NO_PARAM);
        }
        if (recommendDTO.getUserId() == null) {
            throw new CustomException("用户id不能为空");
        }

        User user = userMapper.selectById(recommendDTO.getUserId());
        if (user == null) {
            throw new CustomException("用户不存在，请尝试重新登录");
        }

        List<User> userList = null;
        if (Boolean.TRUE.equals(redisTemplate.hasKey(Constant.PROJECT_NAME + ":" + Constant.USER_LIST))) {
            List<Object> listObj = redisTemplate.opsForList().range(Constant.PROJECT_NAME + ":" + Constant.USER_LIST,
                    0, -1);
            userList = BeanUtil.copyToList(listObj, User.class);
        } else {
            userList = userMapper.selectList(null);
            if (userList.isEmpty()) {
                throw new CustomException("暂无符合要求的用户");
            }
            redisTemplate.opsForList().leftPushAll(Constant.PROJECT_NAME + ":" + Constant.USER_LIST,
                    Common.toSafeUserList(userList).toArray());
        }

        UserVo userVo = new UserVo();
        userVo.setId(1);
        userVo.setNickName("周小白");
        userVo.setStuId("2018210000");
        userVo.setAvatar("https://img-blog.csdnimg.cn/20210524163422807.jpg");

        // 如果要求推荐为异性，且随机推荐
        if (recommendDTO.getIsSex() == 1 && recommendDTO.getIsRandom() == 1) {
            int sex = user.getGender() == 0 ? 1 : 0;
            if (userList == null || userList.isEmpty()) {
                throw new CustomException("暂无符合要求的用户");
            }

            List<User> genderList = userList.stream()
                    .collect(Collectors.groupingBy(User::getGender))
                    .get(sex);
            int randomInt = RandomUtil.randomInt(0, genderList.size());

            return Common.userToUserVo(genderList.get(randomInt));
        }

        // 如果要求推荐不为异性，且随机推荐
        if (recommendDTO.getIsSex() == 0 && recommendDTO.getIsRandom() == 1) {
            if (userList == null || userList.isEmpty()) {
                throw new CustomException("暂无符合要求的用户");
            }
            int randomInt = RandomUtil.randomInt(0, userList.size());
            while (true) {
                if (Objects.equals(userList.get(randomInt).getId(), recommendDTO.getUserId())) {
                    randomInt = RandomUtil.randomInt(0, userList.size());
                } else {
                    break;
                }
            }

            return Common.userToUserVo(userList.get(randomInt));
        }

        // 如果要求推荐为异性，且不随机推荐
        if (recommendDTO.getIsSex() == 1 && recommendDTO.getIsRandom() == 0) {
            int sex = user.getGender() == 0 ? 1 : 0;
            if (userList == null || userList.isEmpty()) {
                throw new CustomException("暂无符合要求的用户");
            }

            List<User> genderList = userList.stream()
                    .collect(Collectors.groupingBy(User::getGender))
                    .get(sex);

            // 将用户的标签转为List
            Gson gson = new Gson();
            List<String> tags = gson.fromJson(user.getTags(),
                    new TypeToken<List<String>>() {}.getType());

            // 计算用户与其他用户的标签相似度
            ArrayList<Pair<User, Integer>> list = new ArrayList<>();
            for (User u : genderList) {
                if (u.getTags() == null) {
                    continue;
                }
                Gson g = new Gson();
                List<String> t = g.fromJson(u.getTags(),
                        new TypeToken<List<String>>() {}.getType());
                int distance = ArithmeticUtils.minDistance(tags, t);
                list.add(Pair.of(u, distance));
            }

            // 按照标签相似度排序
            List<Pair<User, Integer>> sortedList = list.stream()
                    .sorted(Comparator.comparingInt(Pair::getValue))
                    .limit(10)
                    .toList();

            int randomInt = RandomUtil.randomInt(0, sortedList.size());
            User selected = userMapper.selectById(sortedList.get(randomInt)
                    .getKey().getId());

            return Common.userToUserVo(selected);
        }

        // 如果要求推荐不为异性，且不随机推荐
        if (userList == null || userList.isEmpty()) {
            throw new CustomException("暂无符合要求的用户");
        }
        // 将用户的标签转为List
        Gson gson = new Gson();
        List<String> tags = gson.fromJson(user.getTags(),
                new TypeToken<List<String>>() {}.getType());

        // 计算用户与其他用户的标签相似度
        ArrayList<Pair<User, Integer>> list = new ArrayList<>();
        for (User u : userList) {
            if (u.getTags() == null || Objects.equals(u.getId(), recommendDTO.getUserId())) {
                continue;
            }
            Gson g = new Gson();
            List<String> t = g.fromJson(u.getTags(),
                    new TypeToken<List<String>>() {}.getType());
            int distance = ArithmeticUtils.minDistance(tags, t);
            list.add(Pair.of(u, distance));
        }

        // 按照标签相似度排序
        List<Pair<User, Integer>> sortedList = list.stream()
                .sorted(Comparator.comparingInt(Pair::getValue))
                .limit(10)
                .toList();

        int randomInt = RandomUtil.randomInt(0, sortedList.size());
        User selected = userMapper.selectById(sortedList.get(randomInt)
                .getKey().getId());

        return Common.userToUserVo(selected);
    }




    /**
     * 登录
     * @param loginDTO 登录信息
     * @return 登录结果
     */
    @Override
    public LoginVO login(LoginDTO loginDTO) {
        if (loginDTO.getStuId() == null || loginDTO.getPassword() == null) {
            throw new CustomException(ResponseCodeEnum.NO_PARAM);
        }

        LoginVO loginVO = new LoginVO();

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getStuId, loginDTO.getStuId());
        User user = userMapper.selectOne(queryWrapper);
        if (user != null) {
            loginVO.setType(Constant.LOGIN_TYPE_INFO);
            return loginVO;
        }

        String s = HttpUtil.get("http://47.236.23.229:8082/login?username=" +
                loginDTO.getStuId() + "&password=" + loginDTO.getPassword());
        Gson gson = new Gson();
        LoginObject loginObject = gson.fromJson(s, new TypeToken<LoginObject>() {
        }.getType());

        if (loginObject.getCode() == 200) {
            loginVO.setType(Constant.LOGIN_TYPE_NO_INFO);
            return loginVO;
        }  else {
            throw new CustomException("用户名或密码错误");
        }
    }



    /**
     * 获取用户信息
     * @param stuId 学号
     * @return 用户信息
     */
    @Override
    public UserVo getUserInfoByStuId(String stuId) {
        if (stuId == null || stuId.isEmpty()) {
            throw new CustomException("学号不能为空");
        }

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getStuId, stuId);
        User user = userMapper.selectOne(queryWrapper);
        if (user == null) {
            throw new CustomException("用户不存在");
        }

        return Common.userToUserVo(user);
    }
}




